Graphics
Smooth Animation for Games
by John Watson
Your Computer, February 1982, page 52

Producing realistic graphics on the ZX-81 poses few programming problems. Yet
if you then have to make those graphics move, you soon find yourself trapped 
in loops of undreamt-of complexity. John Watson's techniques for animation use
machine-code subroutines, are easy to handle and produce far more polished re-
sults than their Basic counterparts.

The ZX-8l, like many other microcomputers, can print a wide range of graphics
symbols as well as the conventional characters. Yet if you want to draw gra-
phics quickly or to move complicated illustrations around the screen, you will
find the task hampered by the slowness of Basic.

Anyone who has constructed a picture on the ZX-81 using more than a few char-
acters will have noticed the way that Basic builds the picture from the top 
downwards. If the screen is cleared, the picture also disappears from the top 
downwards.

The overall effect is rather like an invisible hand rapidly piling up and then
demolishing building bricks. Space Invaders seem to build and re-build them-
selves in different positions on the screen rather than move about as they do
in the arcade games. It is for this reason that most games involving animated 
graphics are written in machine code. Anyone who has written extensive machine-
code programs will know what a marathon chore it can be - even using an assem-
bler. As an alternative to writing the whole program in machine code, I decided
to write a short, general-purpose machine-code routine for producing drawings 
on the screen. Using the subroutine, anyone can write a Basic program with ani-
mated graphics.

===============================================
Figure 4. See Demo 1.bas
===============================================

The ZX-81 fitted with the 16K RAM pack produces a screen which is effectively
memory-mapped. Mark a sheet of squared paper with 33 squares wide by 24 squares
deep. This corresponds to the printing positions on the screen. Each line on 
the screen has 32 characters, plus an invisible end-of-line character at the 
right-hand end of each line. Screen location number 1 is in the top left-hand 
corner, and the bottom right-hand location is 792.

The only slightly unusual feature of the Sinclair memory-mapped screen is that 
it moves around in memory. However, that is not too much of a problem since you
can locate the beginning of the display file by looking in memory locations 
16396/7. This location actually gives the address of the byte immediately be-
fore the first screen position. The first screen position can therefore be 
found with:
 (PEEK 16396+256*PEEK 16397)+1
and the last screen position with:
 (PEEK 16396+256*PEEK 16397)+791

One word of warning: if you Poke the end-of-line character, you will crash the 
program; if you want to avoid doing this, have the Basic check the screen loc-
ation to make sure it is not evenly divisible by 33. Also ensure that it is
not O - Poking the character before the first position in the screen will also
cause a crash.

The only way to print graphics characters rapidly is with machine code. Rather 
than go through the immense task of writing a machine-code program for every 
graphics game, a subroutine can be used. This machine-code subroutine consists 
of only 56 bytes, and the subroutine and its data lines are housed in a 10-Rem
statement.

Figure 1 shows how the subroutine in Z-80 mnemonics is tucked into Rem state-
ments ready for treatment by the Bug-Byte ZXAS assembler. Alternatively, figure
2 gives a hexadecimal dump of the program. Note that the program itself finish-
es at 40B9 - everything from 40BA onwards is data.

The program begins with five control bytes-4082 hexadecimal equals 16,514 in 
decimal. If location 16514 contains a number other than zero, the program will 
draw a picture from the data. If 16514 contains zero, the program erases the 
drawing using the same data.

Locations 16515 and 16516 are Poked with a number in the range 1 to 791 which 
is the screen position for the start of the drawing. Locations 16517 and 16518 
contain the address of the start of the data for the drawing. These features 
enable you to put in several groups of data, and draw or erase at any position 
on the screen. Even complex drawings appear and disappear from the screen inst-
antly.

To generate, say, a Space Invader, Poke the data location, the position on the 
screen, and the draw/erase control byte. Then call the subroutine with USR. For
the demonstration program, it looks like this:

100 POKE 16514,255	{Selects "draw" as opposed to "erase"

110 POKE 16515,03	{Start drawing at the third 
120 POKE 16516,0	{position on the top line.

130 POKE 16517,186	{Data starts at 40BA --
140 POKE 16518,64 	{64=40 hexadecimal, 186=BA hexadecimal

150 RAND USR 16519

Using this, the picture appears: to erase it again, you need only change one 
location:

200 POKE 16514,0 	Select ''erase''
210 RAND USR 16519	All other parameters are the same, so calL the subroutine

You will see that it vanishes again. To redraw it one step to the right:

300 POKE 16514,255	Select "draw"
310 POKE 16515,04	Start drawing at the fourth position on the top line
320 RAND USR 16519

The data for the machine-code program starts at 40BA hexadecimal which is 
16,570 decimal.  The data determines how the drawing is formed - for an 

===============================================
Figure 2.  See Demo 1.bas
===============================================

explanation we need to return to the 33-by-24 grid. Start by drawing the pic-
ture you want. You can use any printable characters or graphics symbols.  Count
the number of characters to be printed. This, in hexadecimal, is the first byte
of the data. The maximum number of characters in a drawing is 128, or 80 hexa-
decimal - enough for the most ambitious lunar lander. Start with the top line 
of the drawing and take the rightmost character. This is the starting position 
for the drawing, and is the point referred to in the control location in the

===============================================
Figure 1.  See Smooth Graphics.asm
===============================================

main subroutine at 16515 and 16516. The second byte of data is the hexadecimal
code for that character - the codes are Iisted on pages 181-187 of the Sinclair
ZX-81 manual.

The third byte of data is the displacement for the second character to be 
printed. All the displacements are positive. Thus a displacement of one means 
that the next character to be printed will be the one immediately to the right
of the first. A displacement of two means that the next print position is two 
places to the right. Since the displacements are mapped 33 characters to the 
line, a displacement of 33 - 21 hexadecimal - would mean that the next print 
position is immediately under the first one. To put a horizontal black bar on 
the screen, consisting of four inverse spaces, the data line used would be:
			04,80,01,80,01,80,01,80

The first byte records that there are four characters. The second byte is the
code for inverse space, 80 hexadecimal, which is what is to be printed at the 
first position; next is the displacement to the right, one place; then the next
character, also 80 hexadecimal, and so on.

A vertical bar consisting of just three inverse spaces would be:
			03,80.21.80.21.80

Practice writing the data for a few single illustrations before progressing to 
anything too complicated.

[Instructions on how to enter program and hex loader omitted. GCH]

The Basic program shown in figure 4 provides a demonstration of the use of the
subroutine. When you run this program it will produce a picture. In it, the 
alien appears in the top left corner of the screen, cruises horizontally to the
right for a while, descends at an angle, and finally lands vertically in the 
bottom right-hand corner.

The graphic images pop into place almost instantly. The program makes the 
images move by the usual technique of erasing an image and then replacing it 
slightly further along the screen; erasing that one, and replacing it with 
another, and so on. There is still a slight flicker of the image, caused by the
delay between erasing one picture and drawing the next.

This delay occurs while Basic is changing the control values. The flicker can
be minimized by doing as little as possible in Basic between "erase'' and 
"redraw''. This program shows the capabilities of the subroutine, but to pro-
duce graphics which move perfectly smoothly, one of two alternative techniques
can be used. 

The simplest technique is to surround the image of the moving object with a 
halo of spaces. There is no reason, of course, why the subroutine should not be
used to print spaces as well as characters, Provided you then move the drawing 
only one step at a time in any direction, it will automatically erase all 
traces of its previous incarnation as it goes. Data to produce this kind of 
animation is given in figure 5. It is 84 bytes long, which is the main problem
with this technique. The dummy Rem statement will need to be 140 bytes long.
Use the same Basic demonstration program but make the following changes:
         30 POKE 16515,1
         90 POKE l6514,255
         105 IF T<17 THEN LET E=1
and delete line 190.

The second technique is to use different data blocks to erase and redraw only 
the changed parts of a moving drawing. The simplest example is a moving rec-
tangle. If it moves vertically, you need only erase the trailing edge and re-
draw a new front edge. The sides and the middle can be left alone, and the
overall effect is a much smoother movement than you would achieve by eras-
ing and redrawing the whole object. Multiple data blocks can also be used to 
create the various stages of an explosion, for example.

You must be methodical in producing the data for the drawing, but this is a 
small price to pay for the improvement in the program. Finally, watch out for
accidental Poking of the forbidden end-of-line characters in the display file.
If you want to see the effect of doing this, change line 110 of the Basic pro-
gram to read:
   11O IF T>30 THEN LET E=33
and watch the program crash.

===============================================
Figure 5. Revised data for improving the smoothness of animation
          See Demo 2.bas
===============================================